#!/usr/bin/env bash
# vim:ts=4:sw=4:expandtab

############################################################
# NAME
#     mkm - a toy for manager mkx
#
# SYNOPSIS
#     mkm init project-path
#
#     mkm path target [ --global | --system ]
#     mkm list target [ --global | --system ]
#     mkm find target [ --global | --system ] target
#     mkm del  target [ --global | --system ] targets...
#     mkm add  target [ --global | --system ] module-name host-path targets...
#
#     mkm path module [ --global | --system ]
#     mkm list module [ --global | --system ]
#     mkm find module [ --global | --system ]
#     mkm del  module [ --global | --system ] modules...
#     mkm add  module [ --global | --system ] module-name local
#     mkm add  module [ --global | --system ] module-name rsa    username  rsapkey-path hostname  hostport
#     mkm add  module [ --global | --system ] module-name passwd username  password     hostname  hostport
#     mkm add  module [ --global | --system ] module-name custom [config3] [config4]    [config5] [config6]
#     mkm add  module [ --global | --system ] module-name su     username  password     hostname  hostport
#
#     mkm path config [ --global | --system ]
#     mkm list config [ --global | --system ]
#     mkm get  config [ --global | --system ] key [default-config]
#     mkm find config [ --global | --system ] key
#     mkm del  config [ --global | --system ] keys
#     mkm add  config [ --global | --system ] key = vaule
#
#     mkm path command [ --global | --system ]
#     mkm list command [ --global | --system ]
#     mkm find command [ --global | --system ] target [type]
#     mkm del  command [ --global | --system ] target type
#     mkm add  command [ --global | --system ] target type command
#
#     mkm path commandtpl [ --global | --system ]
#     mkm list commandtpl [ --global | --system ]
#     mkm find commandtpl [ --global | --system ] module-name [type]
#     mkm del  commandtpl [ --global | --system ] module-name type
#     mkm add  commandtpl [ --global | --system ] module-name type command
#
#     mkm path targetreg [ --global | --system ]
#     mkm list targetreg [ --global | --system ]
#     mkm find targetreg [ --global | --system ] target
#     mkm add  targetreg [ --global | --system ] module-name host-path regexp
#
#     debug=on mkm ...
#
# AUTHORS
#     neiku project <ku7d@qq.com> 
#
# SEE ALSO
#     mkxrc_modules
#     mkxrc_targets
#     mkxrc_commands
#     mkxrc_commandtpls
#
# VERSION
#     2015/11/26: 支持查看/删除/新增target
#     2015/11/27: 支持查看/删除/新增module
#     2015/11/28: 支持project/global/system级别
#                 target/module/config/command配置(多项目场景)
#     2015/12/03: 支持本地部署模块(local module)
#     2015/12/11: 支持get config自动去掉左边空白(SP/TAB)
#     2015/12/12: bugfix: get config去空白得在find之后马上执行
#                 支持命令模板(可配置不同模块的不同命令模板)
#     2015/12/16: 支持模式匹配target(TODO: 支持del targetreg)
#     2016/02/16: get config支持默认配置
#     2016/03/25: 修复无法正常初始化项目级targetregs配置问题
#     2016/05/28: 支持使用反斜杠作为多行配置的续行符
#                 ( \\\\ 在两个反引号之间等价于 \\ )
#                 ( targetreg 不支持多行配置 )
#     2016/06/18: 支持su module(module type = su)
#     2017/01/16: 支持跨平台
#                 - 通过env程序+PATH变量动态查询bash，控制权
#                   、准确性都得到保障
#
############################################################

# Entity Relationship:
# target(*) <-----> module(1)     <-----> destination(1)
# target(1) <-----> command(*)

mkxrc_targets_sys="/etc/mkxrc_targets"
mkxrc_targets_glo="$HOME/.mkxrc_targets"
mkxrc_targets_prj="`pwd -P`/.mkxrc_targets~"

mkxrc_modules_sys="/etc/mkxrc_modules"
mkxrc_modules_glo="$HOME/.mkxrc_modules"
mkxrc_modules_prj="`pwd -P`/.mkxrc_modules~"

mkxrc_configs_sys="/etc/mkxrc_configs"
mkxrc_configs_glo="$HOME/.mkxrc_configs"
mkxrc_configs_prj="`pwd -P`/.mkxrc_configs~"

mkxrc_commands_sys="/etc/mkxrc_commands"
mkxrc_commands_glo="$HOME/.mkxrc_commands"
mkxrc_commands_prj="`pwd -P`/.mkxrc_commands~"

mkxrc_commandtpls_sys="/etc/mkxrc_commandtpls"
mkxrc_commandtpls_glo="$HOME/.mkxrc_commandtpls"
mkxrc_commandtpls_prj="`pwd -P`/.mkxrc_commandtpls~"

mkxrc_targetregs_sys="/etc/mkxrc_targetregs"
mkxrc_targetregs_glo="$HOME/.mkxrc_targetregs"
mkxrc_targetregs_prj="`pwd -P`/.mkxrc_targetregs~"

function showhelp()
{
    echo "usage:"
    echo "    mkm init project-path"
    echo
    echo "    mkm path target [ --global | --system ]"
    echo "    mkm list target [ --global | --system ]"
    echo "    mkm find target [ --global | --system ] target"
    echo "    mkm del  target [ --global | --system ] targets..."
    echo "    mkm add  target [ --global | --system ] module-name host-path targets..."
    echo
    echo "    mkm path module [ --global | --system ]"
    echo "    mkm list module [ --global | --system ]"
    echo "    mkm find module [ --global | --system ] module"
    echo "    mkm del  module [ --global | --system ] modules..."
    echo "    mkm add  module [ --global | --system ] module-name local"
    echo "    mkm add  module [ --global | --system ] module-name rsa    username  rsapkey-path hostname  hostport"
    echo "    mkm add  module [ --global | --system ] module-name passwd username  password     hostname  hostport"
    echo "    mkm add  module [ --global | --system ] module-name custom [config3] [config4]    [config5] [config6]"
    echo "    mkm add  module [ --global | --system ] module-name su     username  password"
    echo
    echo "    mkm path config [ --global | --system ]"
    echo "    mkm list config [ --global | --system ]"
    echo "    mkm get  config [ --global | --system ] key [default-config]"
    echo "    mkm find config [ --global | --system ] key"
    echo "    mkm del  config [ --global | --system ] keys..."
    echo "    mkm add  config [ --global | --system ] key = value"
    echo
    echo "    mkm path command [ --global | --system ]"
    echo "    mkm list command [ --global | --system ]"
    echo "    mkm find command [ --global | --system ] target [type]"
    echo "    mkm del  command [ --global | --system ] target type"
    echo "    mkm add  command [ --global | --system ] target type command"
    echo
    echo "    mkm path commandtpl [ --global | --system ]"
    echo "    mkm list commandtpl [ --global | --system ]"
    echo "    mkm find commandtpl [ --global | --system ] module-name [type]"
    echo "    mkm del  commandtpl [ --global | --system ] module-name type"
    echo "    mkm add  commandtpl [ --global | --system ] module-name type command"
    echo
    echo "    mkm path targetreg [ --global | --system ]"
    echo "    mkm list targetreg [ --global | --system ]"
    echo "    mkm find targetreg [ --global | --system ] target"
    echo "    mkm add  targetreg [ --global | --system ] module-name host-path regexp"
}

if [ $# -lt 2 ] ; then
    showhelp && exit 1;
fi

cmd="$1"
mod="$2"

if [   "$cmd" != "init" \
    -a "$cmd" != "add"  \
    -a "$cmd" != "list" \
    -a "$cmd" != "find" \
    -a "$cmd" != "del"  \
    -a "$cmd" != "get"  \
    -a "$cmd" != "path" ] ; then
    showhelp && exit 1;
fi
if [   "$cmd" != "init"       \
    -a "$mod" != "target"     \
    -a "$mod" != "module"     \
    -a "$mod" != "config"     \
    -a "$mod" != "command"    \
    -a "$mod" != "commandtpl" \
    -a "$mod" != "targetreg"  ] ; then
    showhelp && exit 1;
fi
if [   "$cmd"  = "get"     \
    -a "$mod" != "config"  ] ; then
    showhelp && exit 1;
fi

shift 2

if [ "$cmd" = "init" ] ; then
    [ -z "$mod" ] && showhelp && exit
    touch "$mod/`basename $mkxrc_targets_prj`"
    touch "$mod/`basename $mkxrc_modules_prj`"
    touch "$mod/`basename $mkxrc_configs_prj`"
    touch "$mod/`basename $mkxrc_commands_prj`"
    touch "$mod/`basename $mkxrc_commandtpls_prj`"
    touch "$mod/`basename $mkxrc_targetregs_prj`"
    echo "init project in $mod/ succ"
fi

if [ $mod = "target" ] ; then
    case "$cmd" in
    find)
        [ -z "$1" ] && showhelp && exit 1
        path="`mkm path target $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            [ -z "$2" ] && showhelp && exit 1
            grep -v -E "^#" "$path" 2>/dev/null \
            | sed 's/^[ \t]*//g' \
            | sed ':begin; N; s/\\[ \t]*\n/ /g; b begin;' \
            | sed 's/\\[ \t]*$//g' \
            | grep -v "^$" \
            | grep -w "$2" \
            | tail -n1
            exit
        fi
        out="`grep -v -E "^#" "$path" 2>/dev/null \
              | sed 's/^[ \t]*//g' \
              | sed ':begin; N; s/\\\\[ \t]*\n/ /g; b begin;' \
              | sed 's/\\\\[ \t]*$//g' \
              | grep -v "^$" \
              | grep -w "$1" \
              | tail -n1`"
        [ -z "$out" ] && out="`mkm find target --global $1`"
        [ -z "$out" ] && out="`mkm find target --system $1`"
        [ -n "$out" ] && echo "$out"
        exit
        ;;
    list)
        path="`mkm path target $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            debug=on mklog debug "# ${1:2}'s targets ($path):"
            [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
            exit
        fi
        debug=on mklog debug "# project's targets ($path):"
        [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
        mkm list target --global
        mkm list target --system
        exit
        ;;
    del)
        path="`mkm path target $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            [ -f "$path" ] \
            && for target in $* ; do
                   sed -i "s/\<$target\>//g" "$path"
                   mklog normal "del ${flag:2} target($target) succ"
               done \
            ||  mklog error "del ${flag:2} target($*) fail"
            exit
        fi
        [ -f "$path" ] \
        && for target in $* ; do
            sed -i "s/\<$target\>//g" "$path"
            mklog normal "del project target($target) succ"
        done \
        ||  mklog error "del project target($*) fail"
        exit
        ;;
    add)
        path="`mkm path target $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            echo "$*" >> "$path" \
            && mklog normal "add ${flag:2}($path) target succ" \
            || mklog error "add ${flag:2}($path) target fail"
            exit
        fi
        echo "$*" >> "$path" \
        && mklog normal "add project($path) target succ" \
        || mklog error "add project($path) target fail"
        exit
        ;;
    path)
        [ "$1" = "--global" ] && echo "$mkxrc_targets_glo" && exit
        [ "$1" = "--system" ] && echo "$mkxrc_targets_sys" && exit
        [ -f "$mkxrc_targets_prj" ] && echo "$mkxrc_targets_prj" && exit
        mkxrc_targets_prj="`dirname $(dirname "$mkxrc_targets_prj")`/`basename "$mkxrc_targets_prj"`"
        while [ "`dirname "$mkxrc_targets_prj"`" != "/" ] ; do
            [ -f "$mkxrc_targets_prj" ] && echo "$mkxrc_targets_prj" && exit
            mkxrc_targets_prj="`dirname $(dirname "$mkxrc_targets_prj")`/`basename "$mkxrc_targets_prj"`"
        done
        mkxrc_targets_prj="`pwd -P`/`basename $mkxrc_targets_prj`"
        echo "$mkxrc_targets_prj"
        exit
        ;;
    esac
fi

if [ $mod = "module" ] ; then
    case "$cmd" in
    find)
        [ -z "$1" ] && showhelp && exit 1
        path="`mkm path module $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            [ -z "$2" ] && showhelp && exit 1
            grep -v -E "^#" "$path" 2>/dev/null \
            | sed 's/^[ \t]*//g' \
            | sed ':begin; N; s/\\[ \t]*\n/ /g; b begin;' \
            | sed 's/\\[ \t]*$//g' \
            | grep -v "^$" \
            | grep -w "^$2" \
            | tail -n1
            exit
        fi
        out="`grep -v -E "^#" "$path" 2>/dev/null \
              | sed 's/^[ \t]*//g' \
              | sed ':begin; N; s/\\\\[ \t]*\n/ /g; b begin;' \
              | sed 's/\\\\[ \t]*$//g' \
              | grep -v "^$" \
              | grep -w "^$1" \
              | tail -n1`"
        [ -z "$out" ] && out="`mkm find module --global $1`"
        [ -z "$out" ] && out="`mkm find module --system $1`"
        [ -n "$out" ] && echo "$out"
        exit
        ;;
    add)
        path="`mkm path module $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            [ $# -lt 2 ] && showhelp && exit 1
            [ "$2" != "rsa" -a "$2" != "local" -a "$2" != "passwd" ] && showhelp && exit 1
            [ "$2" = "rsa" -a $# -lt 6 ] && showhelp && exit 1
            [ "$2" = "passwd" -a $# -lt 6 ] && showhelp && exit 1
            echo "$*" >> "$path" \
            && mklog normal "add ${flag:2}($path) module succ" \
            || mklog error "add ${flag:2}($path) module fail"
            exit
        fi
        [ $# -lt 2 ] && showhelp && exit 1
        [    "$2" != "rsa"    \
          -a "$2" != "local"  \
          -a "$2" != "passwd" \
          -a "$2" != "custom" \
          -a "$2" != "su"     ] && showhelp && exit 1
        [ "$2" = "rsa" -a $# -lt 6 ] && showhelp && exit 1
        [ "$2" = "passwd" -a $# -lt 6 ] && showhelp && exit 1
        [ "$2" = "su" -a $# -lt 2 ] && showhelp && exit 1
        echo "$*" >> "$path" \
        && mklog normal "add project($path) module succ" \
        || mklog error "add project($path) module fail"
        exit
        ;;
    list)
        path="`mkm path module $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            debug=on mklog debug "# ${1:2}'s modules ($path):"
            [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
            exit
        fi
        debug=on mklog debug "# project's modules ($path):"
        [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
        mkm list module --global
        mkm list module --system
        exit
        ;;
    del)
        path="`mkm path module $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            [ -f "$path" ] \
            && for module in $* ; do
                   sed -i "/^$module[ \t]/d" "$path"
                   mklog normal "del ${flag:2} module($module) succ"
               done \
            ||  mklog error "del ${flag:2} module($*) fail"
            exit
        fi
        [ -f "$path" ] \
        && for module in $* ; do
            sed -i "/^$module[ \t]/d" "$path"
            mklog normal "del project module($module) succ"
        done \
        ||  mklog error "del project module($*) fail"
        exit
        ;;
    path)
        [ "$1" = "--global" ] && echo "$mkxrc_modules_glo" && exit
        [ "$1" = "--system" ] && echo "$mkxrc_modules_sys" && exit
        [ -f "$mkxrc_modules_prj" ] && echo "$mkxrc_modules_prj" && exit
        mkxrc_modules_prj="`dirname $(dirname "$mkxrc_modules_prj")`/`basename "$mkxrc_modules_prj"`"
        while [ "`dirname "$mkxrc_modules_prj"`" != "/" ] ; do
            [ -f "$mkxrc_modules_prj" ] && echo "$mkxrc_modules_prj" && exit
            mkxrc_modules_prj="`dirname $(dirname "$mkxrc_modules_prj")`/`basename "$mkxrc_modules_prj"`"
        done
        mkxrc_modules_prj="`pwd -P`/`basename $mkxrc_modules_prj`"
        echo "$mkxrc_modules_prj"
        exit
        ;;
    esac 
fi

if [ $mod = "config" ] ; then
    case "$cmd" in
    get)
        [ -z "$1" ] && showhelp && exit 1
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            [ -z "$2" ] && showhelp && exit 1
            val="`mkm find config $1 $2 | sed "s/^[ \t]*$2[ \t]*=[ \t]*//g"`"
            [ -z "$val" ] && val="$3"
            [ -n "$val" ] && echo "$val"
            exit
        fi
        val="`mkm find config $1 $2 | sed "s/^[ \t]*$1[ \t]*=[ \t]*//g"`"
        [ -z "$val" ] && val="`mkm find config --global $1`"
        [ -z "$val" ] && val="`mkm find config --system $1`"
        [ -z "$val" ] && val="$2"
        [ -n "$val" ] && echo "$val"
        exit
        ;;
    find)
        [ -z "$1" ] && showhelp && exit 1
        path="`mkm path config $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            [ -z "$2" ] && showhelp && exit 1
            grep -v -E "^#" "$path" 2>/dev/null \
            | sed 's/^[ \t]*//g' \
            | sed ':begin; N; s/\\[ \t]*\n/ /g; b begin;' \
            | sed 's/\\[ \t]*$//g' \
            | grep -v "^$" \
            | grep -P "^[ \t]*$2[ \t]*=" \
            | tail -n1
            exit
        fi
        out="`grep -v -E "^#" "$path" 2>/dev/null \
              | sed 's/^[ \t]*//g' \
              | sed ':begin; N; s/\\\\[ \t]*\n/ /g; b begin;' \
              | sed 's/\\\\[ \t]*$//g' \
              | grep -v "^$" \
              | grep -P "^[ \t]*$1[ \t]*=" \
              | tail -n1`"
        [ -z "$out" ] && out="`mkm find config --global $1`"
        [ -z "$out" ] && out="`mkm find config --system $1`"
        [ -n "$out" ] && echo "$out"
        exit
        ;;
    add)
        path="`mkm path config $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            echo "$*" >> "$path" \
            && mklog normal "add ${flag:2}($path) config succ" \
            || mklog error "add ${flag:2}($path) config fail"
            exit
        fi
        echo "$*" >> "$path" \
        && mklog normal "add project($path) config succ" \
        || mklog error "add project($path) config fail"
        exit
        ;;
    list)
        path="`mkm path config $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            debug=on mklog debug "# ${1:2}'s configs ($path):"
            [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
            exit
        fi
        debug=on mklog debug "# project's configs ($path):"
        [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
        mkm list config --global
        mkm list config --system
        exit
        ;;
    del)
        path="`mkm path config $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            [ -f "$path" ] \
            && for config in $* ; do
                   sed -i "/^[ \t]*$config[ \t]*=/d" "$path"
                   mklog normal "del ${flag:2} config($config) succ"
               done \
            ||  mklog error "del ${flag:2} config($*) fail"
            exit
        fi
        [ -f "$path" ] \
        && for config in $* ; do
        sed -i "/^[ \t]*$config[ \t]*=/d" "$path"
            mklog normal "del project config($config) succ"
        done \
        ||  mklog error "del project config($*) fail"
        exit
        ;;
    path)
        [ "$1" = "--global" ] && echo "$mkxrc_configs_glo" && exit
        [ "$1" = "--system" ] && echo "$mkxrc_configs_sys" && exit
        [ -f "$mkxrc_configs_prj" ] && echo "$mkxrc_configs_prj" && exit
        mkxrc_configs_prj="`dirname $(dirname "$mkxrc_configs_prj")`/`basename "$mkxrc_configs_prj"`"
        while [ "`dirname "$mkxrc_configs_prj"`" != "/" ] ; do
            [ -f "$mkxrc_configs_prj" ] && echo "$mkxrc_configs_prj" && exit
            mkxrc_configs_prj="`dirname $(dirname "$mkxrc_configs_prj")`/`basename "$mkxrc_configs_prj"`"
        done
        mkxrc_configs_prj="`pwd -P`/`basename $mkxrc_configs_prj`"
        echo "$mkxrc_configs_prj"
        exit
        ;;
    esac
fi

if [ $mod = "command" ] ; then
    case "$cmd" in
    find)
        # [ --global | --system ] target [type]
        [ -z "$1" ] && showhelp && exit 1
        path="`mkm path command $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            [ -z "$2" ] && showhelp && exit 1
            out="`grep -v -E "^#" "$path" 2>/dev/null \
                  | sed 's/^[ \t]*//g' \
                  | sed ':begin; N; s/\\\\[ \t]*\n/ /g; b begin;' \
                  | sed 's/\\\\[ \t]*$//g' \
                  | grep -v "^$" \
                  | grep -w -P "^$2[ \t]*"`"
            [ -z "$out" ] && exit
            [ -z "$3" ] && echo "$out" && exit
            echo "$out" | grep -P "^$2[ \t]*$3" | tail -n1 && exit
        fi
        out="`grep -v -E "^#" "$path" 2>/dev/null \
              | sed 's/^[ \t]*//g' \
              | sed ':begin; N; s/\\\\[ \t]*\n/ /g; b begin;' \
              | sed 's/\\\\[ \t]*$//g' \
              | grep -v "^$" \
              | grep -w -P "^$1[ \t]*"`"
        [ -n "$out" -a -z "$2" ] \
        && mkm find command --system $1 \
        && mkm find command --global $1 \
        && echo "$out" \
        && exit
        [ -n "$out" -a -n "$2" ] \
        && out="`echo "$out" | grep -P "^$1[ \t]*$2" | tail -n1`"
        [ -z "$out" ] && out="`mkm find command --global $1 $2`"
        [ -z "$out" ] && out="`mkm find command --system $1 $2`"
        [ -n "$out" ] && echo "$out"
        exit
        ;;
    add)
        path="`mkm path command $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            echo "$*" >> "$path" \
            && mklog normal "add ${flag:2}($path) command succ" \
            || mklog error "add ${flag:2}($path) command fail"
            exit
        fi
        echo "$*" >> "$path" \
        && mklog normal "add project($path) command succ" \
        || mklog error "add project($path) command fail"
        exit
        ;;
    list)
        path="`mkm path command $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            debug=on mklog debug "# ${1:2}'s commands ($path):"
            [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
            exit
        fi
        debug=on mklog debug "# project's commands ($path):"
        [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
        mkm list command --global
        mkm list command --system
        exit
        ;;
    del)
        path="`mkm path command $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            [ $# -lt 2 ] && showhelp && exit 1
            [ -f "$path" ] \
            && sed -i "/^[ \t]*$1[ \t]$2/d" "$path" \
            && mklog normal "del ${flag:2} command($1 $2) succ" \
            || mklog error "del ${flag:2} command($1 $2) fail"
            exit
        fi
        [ $# -lt 2 ] && showhelp && exit 1
        [ -f "$path" ] \
        && sed -i "/^[ \t]*$1[ \t]$2/d" "$path" \
        && mklog normal "del project command($1 $2) succ" \
        || mklog error "del project command($1 $2) fail"
        exit
        ;;
    path)
        [ "$1" = "--global" ] && echo "$mkxrc_commands_glo" && exit
        [ "$1" = "--system" ] && echo "$mkxrc_commands_sys" && exit
        [ -f "$mkxrc_commands_prj" ] && echo "$mkxrc_commands_prj" && exit
        mkxrc_commands_prj="`dirname $(dirname "$mkxrc_commands_prj")`/`basename "$mkxrc_commands_prj"`"
        while [ "`dirname "$mkxrc_commands_prj"`" != "/" ] ; do
            [ -f "$mkxrc_commands_prj" ] && echo "$mkxrc_commands_prj" && exit
            mkxrc_commands_prj="`dirname $(dirname "$mkxrc_commands_prj")`/`basename "$mkxrc_commands_prj"`"
        done
        mkxrc_commands_prj="`pwd -P`/`basename $mkxrc_commands_prj`"
        echo "$mkxrc_commands_prj"
        exit
        ;;
    esac
fi

if [ $mod = "commandtpl" ] ; then
    case "$cmd" in
    find)
        # [ --global | --system ] target [type]
        [ -z "$1" ] && showhelp && exit 1
        path="`mkm path commandtpl $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            [ -z "$2" ] && showhelp && exit 1
            out="`grep -v -E "^#" "$path" 2>/dev/null \
                  | sed 's/^[ \t]*//g' \
                  | sed ':begin; N; s/\\\\[ \t]*\n/ /g; b begin;' \
                  | sed 's/\\\\[ \t]*$//g' \
                  | grep -v "^$" \
                  | grep -w -P "^$2[ \t]*"`"
            [ -z "$out" ] && exit
            [ -z "$3" ] && echo "$out" && exit
            echo "$out" | grep -P "^$2[ \t]*$3" | tail -n1 && exit
        fi
        out="`grep -v -E "^#" "$path" 2>/dev/null \
              | sed 's/^[ \t]*//g' \
              | sed ':begin; N; s/\\\\[ \t]*\n/ /g; b begin;' \
              | sed 's/\\\\[ \t]*$//g' \
              | grep -v "^$" \
              | grep -w -P "^$1[ \t]*"`"
        [ -n "$out" -a -z "$2" ] \
        && mkm find commandtpl --system $1 \
        && mkm find commandtpl --global $1 \
        && echo "$out" \
        && exit
        [ -n "$out" -a -n "$2" ] \
        && out="`echo "$out" | grep -P "^$1[ \t]*$2" | tail -n1`"
        [ -z "$out" ] && out="`mkm find commandtpl --global $1 $2`"
        [ -z "$out" ] && out="`mkm find commandtpl --system $1 $2`"
        [ -n "$out" ] && echo "$out"
        exit
        ;;
    add)
        path="`mkm path commandtpl $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            echo "$*" >> "$path" \
            && mklog normal "add ${flag:2}($path) commandtpl succ" \
            || mklog error "add ${flag:2}($path) commandtpl fail"
            exit
        fi
        echo "$*" >> "$path" \
        && mklog normal "add project($path) commandtpl succ" \
        || mklog error "add project($path) commandtpl fail"
        exit
        ;;
    list)
        path="`mkm path commandtpl $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            debug=on mklog debug "# ${1:2}'s commandtpl ($path):"
            [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
            exit
        fi
        debug=on mklog debug "# project's commandtpl ($path):"
        [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
        mkm list commandtpl --global
        mkm list commandtpl --system
        exit
        ;;
    del)
        path="`mkm path commandtpl $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            [ $# -lt 2 ] && showhelp && exit 1
            [ -f "$path" ] \
            && sed -i "/^[ \t]*$1[ \t]$2/d" "$path" \
            && mklog normal "del ${flag:2} commandtpl($1 $2) succ" \
            || mklog error "del ${flag:2} commandtpl($1 $2) fail"
            exit
        fi
        [ $# -lt 2 ] && showhelp && exit 1
        [ -f "$path" ] \
        && sed -i "/^[ \t]*$1[ \t]$2/d" "$path" \
        && mklog normal "del project commandtpl($1 $2) succ" \
        || mklog error "del project commandtpl($1 $2) fail"
        exit
        ;;
    path)
        [ "$1" = "--global" ] && echo "$mkxrc_commandtpls_glo" && exit
        [ "$1" = "--system" ] && echo "$mkxrc_commandtpls_sys" && exit
        [ -f "$mkxrc_commandtpls_prj" ] && echo "$mkxrc_commandtpls_prj" && exit
        mkxrc_commandtpls_prj="`dirname $(dirname "$mkxrc_commandtpls_prj")`/`basename "$mkxrc_commandtpls_prj"`"
        while [ "`dirname "$mkxrc_commandtpls_prj"`" != "/" ] ; do
            [ -f "$mkxrc_commandtpls_prj" ] && echo "$mkxrc_commandtpls_prj" && exit
            mkxrc_commandtpls_prj="`dirname $(dirname "$mkxrc_commandtpls_prj")`/`basename "$mkxrc_commandtpls_prj"`"
        done
        mkxrc_commandtpls_prj="`pwd -P`/`basename $mkxrc_commandtpls_prj`"
        echo "$mkxrc_commandtpls_prj"
        exit
        ;;
    esac
fi

if [ $mod = "targetreg" ] ; then
    case "$cmd" in
    find)
        [ -z "$1" ] && showhelp && exit 1
        path="`mkm path targetreg $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            [ -z "$2" ] && showhelp && exit 1
            grep -v -E "^#|^$" "$path" 2>/dev/null \
            | tac \
            | while read module hostpath regexp ; do
                if echo "$2" | grep -P "$regexp" >/dev/null 2>&1; then
                    echo "$module $hostpath $regexp"
                    break
                fi
            done
            exit
        fi
        out="`grep -v -E "^#|^$" "$path" 2>/dev/null \
            | tac \
            | while read module hostpath regexp ; do
                if echo "$1" | grep -P "$regexp" >/dev/null 2>&1; then
                    echo "$module $hostpath $regexp"
                    break
                fi
            done`"
        [ -z "$out" ] && out="`mkm find targetreg --global $1`"
        [ -z "$out" ] && out="`mkm find targetreg --system $1`"
        [ -n "$out" ] && echo "$out"
        exit
        ;;
    list)
        path="`mkm path targetreg $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            debug=on mklog debug "# ${1:2}'s targetregs ($path):"
            [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
            exit
        fi
        debug=on mklog debug "# project's targetregs ($path):"
        [ -s "$path" ] && cat "$path" | grep -v -E "^#|^$"
        mkm list targetreg --global
        mkm list targetreg --system
        exit
        ;;
    del) # TODO: targetreg 本身是正则表达式
        mklog error "'mkm del targetreg' command not supported now!"
        exit
        ;;
    add)
        path="`mkm path targetreg $1`"
        if [ "$1" = "--global" -o "$1" = "--system" ] ; then
            flag="$1"
            shift 1
            echo "$*" >> "$path" \
            && mklog normal "add ${flag:2}($path) targetreg succ" \
            || mklog error "add ${flag:2}($path) targetreg fail"
            exit
        fi
        echo "$*" >> "$path" \
        && mklog normal "add project($path) targetreg succ" \
        || mklog error "add project($path) targetreg fail"
        exit
        ;;
    path)
        [ "$1" = "--global" ] && echo "$mkxrc_targetregs_glo" && exit
        [ "$1" = "--system" ] && echo "$mkxrc_targetregs_sys" && exit
        [ -f "$mkxrc_targetregs_prj" ] && echo "$mkxrc_targetregs_prj" && exit
        mkxrc_targetregs_prj="`dirname $(dirname "$mkxrc_targetregs_prj")`/`basename "$mkxrc_targetregs_prj"`"
        while [ "`dirname "$mkxrc_targetregs_prj"`" != "/" ] ; do
            [ -f "$mkxrc_targetregs_prj" ] && echo "$mkxrc_targetregs_prj" && exit
            mkxrc_targetregs_prj="`dirname $(dirname "$mkxrc_targetregs_prj")`/`basename "$mkxrc_targetregs_prj"`"
        done
        mkxrc_targetregs_prj="`pwd -P`/`basename $mkxrc_targetregs_prj`"
        echo "$mkxrc_targetregs_prj"
        exit
        ;;
    esac
fi
